﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using MimeKit;
using MimeKit.Text;
using System;
using System.Collections.Generic;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MailKit.Net.Smtp;
using System.Net.Http;
using Org.BouncyCastle.Crypto.Digests;
using System.Linq;
using NLog.Targets.Wrappers;

namespace HS.EIP.WatchService
{
    class WatchHostService : IHostedService
    {
        ServiceWatchOptions options = new ServiceWatchOptions();

        CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
        Task task = null;
        ILogger logger;
        public WatchHostService(IServiceProvider serviceProvider, IConfiguration configuration)
        {
            configuration.Bind("ServiceWatch", options);
            logger = serviceProvider.GetLogger<WatchHostService>();
        }
        public Task StartAsync(CancellationToken cancellationToken)
        {
            task = Excute();
            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            CancellationTokenSource.Cancel();
            this.task?.Wait();
            return Task.CompletedTask;
        }

        //private void Excute1()
        //{
        //    var services = options.Services.Where(o => o.Enable == true);
        //    task = Task.Factory.StartNew(async () =>
        //    {
        //        logger.LogInformation("-------------------------------------------------------------");
        //        logger.LogInformation($"{options.StartupDelay}秒后开始执行服务启动进程。。。");
        //        await Task.Delay(options.StartupDelay * 1000);
        //        logger.LogInformation($"开始执行服务启动进程。");
        //        if (!options.Services.AnyEX())
        //        {
        //            logger.LogInformation($"没有配置需求启动的服务。");
        //            SendAsync($"没有配置需求启动的服务。");
        //            return;
        //        }

        //        foreach (var service in services)
        //        {
        //            if (CancellationTokenSource.IsCancellationRequested) return;

        //            logger.LogInformation("-------------------------------------------------------------");
        //            logger.LogInformation($"开始启动服务【{service.Description}】。");
        //            bool flag = false;
        //            Exception ex = null;
        //            try
        //            {
        //                switch (service.Category)
        //                {
        //                    case "Service":
        //                        {
        //                            if (RunService(service)) flag = true;
        //                        }
        //                        break;
        //                    case "Bat":
        //                        {
        //                            if (await RunBat(service)) flag = true;
        //                        }
        //                        break;
        //                    case "Exe":
        //                        {
        //                            if (await RunExe(service)) flag = true;
        //                        }
        //                        break;
        //                    case "InstallService":
        //                        /**
        //                         * 先卸载已有的服务
        //                         * **/
        //                        //await installService.StopAsync(cancelToken);
        //                        /***
        //                         * 再安装服务，后面守护进程直接启动
        //                         * ***/
        //                        //await installService.StartAsync(cancelToken);
        //                        break;
        //                    default: break;
        //                }
        //            }
        //            catch (Exception e)
        //            {
        //                ex = e;
        //            }

        //            if (flag)
        //            {
        //                logger.LogInformation($"服务【{service.Description}】启动成功。");
        //                SendAsync($"服务【{service.Description}】启动成功。");
        //                await Task.Delay(service.Delay * 1000);
        //            }
        //            else
        //            {
        //                logger.LogError(ex, $"服务【{service.Description}】启动失败,请检查服务，监控程序将停止后续的服务启动操作。");
        //                SendAsync($"服务【{service.Description}】启动失败。=》{ex?.Message}");
        //                return;
        //            }
        //        }

        //        logger.LogInformation("*************************************************************");
        //        logger.LogInformation("*************************************************************");
        //        logger.LogInformation("*************************************************************");
        //        logger.LogInformation("*************************************************************");
        //        logger.LogInformation($"开始执行服务监控进程。");

        //        while (true)
        //        {
        //            foreach (var service in services)
        //            {
        //                if (CancellationTokenSource.IsCancellationRequested) return;
        //                logger.LogInformation("-------------------------------------------------------------");
        //                logger.LogInformation($"开始监控服务【{service.Description}】。");

        //                bool flag = false;
        //                Exception ex = null;
        //                try
        //                {
        //                    switch (service.Category)
        //                    {
        //                        case "Service":
        //                            {
        //                                if (RunService(service)) flag = true;
        //                            }
        //                            break;
        //                        case "Bat":
        //                            {
        //                                if (await RunBat(service)) flag = true;
        //                            }
        //                            break;
        //                        case "Exe":
        //                            {
        //                                if (await RunExe(service)) flag = true;
        //                            }
        //                            break;
        //                        case "InstallService":
        //                            break;
        //                    }
        //                }
        //                catch (Exception e)
        //                {
        //                    ex = e;
        //                }

        //                if (flag)
        //                {
        //                    logger.LogInformation($"服务【{service.Description}】正常运行。");
        //                }
        //                else
        //                {
        //                    logger.LogError(ex, $"服务【{service.Description}】启动失败。");
        //                    SendAsync($"服务【{service.Description}】启动失败。=》{ex?.Message}");
        //                }
        //                await Task.Delay(2000);
        //            }
        //            await Task.Delay(options.WatchInterval * 1000);
        //        }
        //    }, TaskCreationOptions.LongRunning);
        //}

        private async Task Excute()
        {

            logger.LogInformation("-------------------------------------------------------------");
            logger.LogInformation($"{options.StartupDelay}秒后开始执行服务启动进程。。。");
            await Task.Delay(options.StartupDelay * 1000);

            logger.LogInformation($"开始执行服务监控进程。");
            if (!options.Services.AnyEX())
            {
                logger.LogInformation($"没有配置待启动的服务。");
                SendEMailAsync($"没有配置待启动的服务。");
                return;
            }

            var services = options.Services.Where(o => o.Enable == true);
            while (true)
            {
                foreach (var service in services)
                {
                    Repeat:
                    if (CancellationTokenSource.IsCancellationRequested) return;

                    logger.LogInformation("-------------------------------------------------------------");
                    logger.LogInformation($"开始启动服务【{service.Description}】。");
                    //NLogHelp.InfoLog($"开始启动服务【{service.Description}】。");

                    bool flag = false;//启动成功标识
                    Exception ex = null;
                    try
                    {
                        switch (service.Category)
                        {
                            case "Service":
                                {
                                    if (await RunService(service)) flag = true;
                                }
                                break;
                            case "Bat":
                                {
                                    if (await RunBat(service)) flag = true;
                                }
                                break;
                            case "Exe":
                                {
                                    if (await RunExe(service)) flag = true;
                                }
                                break;
                            case "InstallService":
                                /**
                                 * 先卸载已有的服务
                                 * **/
                                //await installService.StopAsync(cancelToken);
                                /***
                                 * 再安装服务，后面守护进程直接启动
                                 * ***/
                                //await installService.StartAsync(cancelToken);
                                break;
                            default: break;
                        }
                    }
                    catch (Exception e)
                    {
                        ex = e;
                    }

                    if (flag)
                    {
                        logger.LogInformation($"服务【{service.Description}】启动成功。");
                        //NLogHelp.InfoLog($"开始启动服务【{service.Description}】。");

                        SendEMailAsync($"服务【{service.Description}】启动成功。");
                        await Task.Delay(service.Delay * 1000);
                    }
                    else
                    {
                        //logger.LogError(ex, $"服务【{service.Description}】启动失败,请检查服务，监控程序将停止后续的服务启动操作。");
                        //NLogHelp.ErrorLog($"服务【{service.Description}】启动失败,请检查服务，监控程序将停止后续的服务启动操作。", ex);
                        logger.LogError(ex, $"服务【{service.Description}】启动失败,请检查服务，监控程序将重复执行服务启动操作。");
                        NLogHelp.ErrorLog($"服务【{service.Description}】启动失败,请检查服务，监控程序将重复执行服务启动操作。", ex);

                        SendEMailAsync($"服务【{service.Description}】启动失败。=》{ex?.Message}");

                        await Task.Delay(service.Delay * 1000);

                        goto Repeat; //重复执行还是直接停止后续？

                        //return;
                    }
                }
            }            
        }
        private Task<bool> RunService(Service service)
        {
            ServiceController sc = null;
            try
            {
                if (LinkService(service, out sc))
                {
                    ServiceControllerStatus st = sc.Status;
                    switch (st)
                    {
                        case ServiceControllerStatus.StopPending:
                        case ServiceControllerStatus.Stopped:
                            sc.Start();
                            break;
                        default: break;
                    }
                    sc.WaitForStatus(ServiceControllerStatus.Running);
                    st = sc.Status;//再次获取服务状态  
                    if (st != ServiceControllerStatus.Running)
                    {
                        return Task.FromResult(false);
                        //Console.WriteLine($"服务【{servername}】启动失败。");
                    }
                    return Task.FromResult(true);
                }
                else
                {
                    logger.LogError($"服务【{service.Name}】不存在。");
                    return Task.FromResult(false);
                }
            }
            finally
            {
                sc?.Dispose();
            }
        }
        private async Task<bool> RunBat(Service service)
        {
            if (service.Loop != 0 && (await HttpHealthCheck.Health(service)))
            {
                return true;
            }
            logger.LogWarning($"服务【{service.Description}】未启动或已停止。。。");
            logger.LogInformation($"开始执行服务【{service.Description}】的批处理命令=》路径：【{service.Name}】。");
            //NLogHelp.InfoLog($"开始执行服务【{service.Description}】的批处理命令=》路径：【{service.Name}】。");

             ExecHelper.ExecBat(service.Name, true, service.WaitForExit);

            //logger.LogInformation($"正常输出结果=》{reslut.OutPutString}");
            //logger.LogError($"错误输出结果=》{reslut.ErrorString}");
            //logger.LogError($"异常输出结果=》{reslut.ErrMsg?.Message}");

            if (service.Loop == 0) return true;

            int loop = service.Loop;
            while (true)
            {
                if (CancellationTokenSource.IsCancellationRequested) break;

                if ((await HttpHealthCheck.Health(service)))
                {
                    logger.LogInformation($"服务【{service.Description}】正在运行。。。");
                    //NLogHelp.InfoLog($"服务【{service.Description}】正在运行。。。");

                    return true;
                }
                else
                {
                    logger.LogError($"服务【{service.Description}】未启动或已停止，执行循环健康检查操作。。。");
                    //NLogHelp.ErrorLog($"服务【{service.Description}】未启动或已停止，执行循环健康检查操作。。。", null);

                    await Task.Delay(service.Interval * 1000);
                }
                if (service.Loop > 0)
                {
                    loop--;
                    if (loop == 0) break;
                }
            }

            return false;
        }
        private async Task<bool> RunExe(Service service)
        {
            if ((await HttpHealthCheck.Health(service)))
            {
                return true;
            }
            logger.LogWarning($"服务【{service.Description}】未启动或已停止。。。");
            logger.LogInformation($"开始执行服务【{service.Description}】的执行程序》路径：【{service.Name}】。");

            var reslut = ExecHelper.ExecBat(service.Name, true, service.WaitForExit);

            //logger.LogInformation($"正常输出结果=》{reslut.OutPutString}");
            //logger.LogError($"错误输出结果=》{reslut.ErrorString}");
            //logger.LogError($"异常输出结果=》{reslut.ErrMsg?.Message}");

            int loop = service.Loop + 1;
            for (var i = 0; i < loop; i++)
            {
                if (CancellationTokenSource.IsCancellationRequested) break;

                if ((await HttpHealthCheck.Health(service)))
                {
                    logger.LogInformation($"服务【{service.Description}】正在运行。。。");
                    return true;
                }
                else
                {
                    logger.LogError($"服务【{service.Description}】未启动或已停止，执行循环健康检查操作。。。");
                    await Task.Delay(service.Interval * 1000);
                }
            }
            return false;
        }

        /// <summary>
        /// 连接服务
        /// </summary>
        /// <param name="servicename"></param>
        /// <param name="controller"></param>
        /// <returns></returns>
        private static bool LinkService(Service service, out ServiceController controller)
        {
            controller = null;
            try
            {
                controller = new ServiceController(service.Name);
                var s = controller.Status;
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 发送电子邮件
        /// </summary>
        /// <param name="content"></param>
        private async void SendEMailAsync(string content)
        {
            if (!options.MailServer.Enable) return;
            try
            {
                var senderAccount = options.MailServer.SendAccount;
                var senderName = "服务守护进程";
                var fromAddress = new List<MailboxAddress>()
            {
                new MailboxAddress(senderName,senderAccount)
            };
                var toAddressList = new List<MailboxAddress>();

                foreach (var item in options.MailServer.Rreceivers)
                {
                    toAddressList.Add(new MailboxAddress(item));
                }


                var message = new MimeMessage();
                message.From.AddRange(fromAddress);
                message.To.AddRange(toAddressList);
                message.Subject = "服务守护进程状态报告";
                var body = new TextPart(TextFormat.Html)
                {
                    Text = content
                };
                MimeEntity entity = body;

                message.Body = entity;
                message.Date = DateTime.Now;
                using (var client = new SmtpClient())
                {
                    //创建连接
                    await client.ConnectAsync(options.MailServer.Host, options.MailServer.Port, options.MailServer.UseSsl);
                    await client.AuthenticateAsync(options.MailServer.SendAccount, options.MailServer.Password);
                    await client.SendAsync(message);
                    await client.DisconnectAsync(true);
                }
            }
            catch (Exception ex)
            {
                this.logger.LogError(ex, "邮件发送失败。");
                NLogHelp.ErrorLog("邮件发送失败。", ex);
            }
        }
    }
}
